//module: memory for data storage
//no external explicit clock signal, controlled by cpu

module DataMem (addr_a, in_val, we, reset, out_a);
  parameter word_size=32;
  parameter addr_size=32;
  parameter mem_size=64;
  parameter MEM_BOUND=32'h0000_0040;
  parameter VAL_ZERO=32'h0;
  parameter VAL_B=32'hBBBB_BBBB;
  //data memory is implemented as a 64-word storage, 256byte




  input [addr_size-1:0] addr_a;
  input [word_size-1:0] in_val;
  input we; //enable control signal
  input reset;
  output [word_size-1:0] out_a; //output memory data from

  reg out_a;

  //internal storage
  reg [word_size-1:0] storage [mem_size-1:0];

  //only for reset
  reg [7:0] counter;



  always @ (reset) begin
      if(reset==1'b1) begin
        for(counter=0;counter<MEM_BOUND;counter=counter+1) begin
            storage[counter]<=VAL_ZERO;
        end
      end
  end

  always @ (we or addr_a or in_val) begin
      //write enable
      if(we==1'b1) begin
          //check bounds
          out_a=32'b0; //set default, remove uncertainty
          if(addr_a<=MEM_BOUND) begin
              storage[addr_a]<=in_val;
          end
          else begin
              $display("Data Mem: Bad W Address:%x, Out of Bound %x", addr_a, MEM_BOUND);
          end
      end
      //read enable
      else begin
      //check bounds
        if(addr_a < MEM_BOUND) begin
            out_a<=storage[addr_a];
        end
        else begin
            $display("Bad R Address:%x, Out of Bound %x", addr_a, MEM_BOUND);
            out_a<=VAL_ZERO; //bad read will return default value
        end
      end
  end


endmodule //implementation of data memory module

// module data_mem_sim ();
//   parameter word_size=32;
//   parameter addr_size=32;
//
//   reg [word_size-1:0] in_val;
//   wire [word_size-1:0] out_val;
//   reg [addr_size-1:0] addr_a;
//   reg we;
//   reg reset;
//
//   DataMem data_mem(addr_a, in_val, we, reset, out_val);
//
//   initial begin
//     $dumpfile("data_mem_sim.vcd");
//     $dumpvars(0,data_mem_sim);
//
//     //init registers
//     we=0;
//     in_val=32'b0;
//     addr_a=32'b0;
//     reset=0;
//
//     //register monitor
//     $display("Time\tWe\tAddr_a\tIn_val\tOut_val");
//     $monitor("%g\t%x\t%x\t%x\t%x",$time, we, addr_a, in_val, out_val);
//
//     //begin simulation
//     //test normal write
//     #1 reset=1;
//     #1 we=1;
//     #2 in_val=32'hF000_F000;
//     //test normal read
//     #2 we=0;
//     #2 addr_a=32'h0000_000E;
//     //test read out of bound
//     #2 addr_a=32'h0000_0E00;
//     //test write out of bound
//     #2 we=1;
//     #2 $finish;
//
//
//
//   end
//
// endmodule // simulator for data memory
